﻿using UnityEngine;
using System.Collections;
#if UNITY_EDITOR
using UnityEditor;
#endif

namespace GBFramework
{
    public abstract class AssetBundleLoadOperation : IEnumerator
    {
        public string m_AssetBundleName;

        //停止下载AB包的标识位(使用：游戏中释放lua的时候，刚好还有资源正在下载，
        //这时候要调用StopAllProgressOperations()方法，将所有的正在下载的资源中止下载，并将AssetBundleLoadOperation对象中的isStop属性设置为true,
        //设置isStop标识位目的是为了不让资源加载完后调用回调方法)
        public bool isStop = false;

        public object Current
        {
            get
            {
                return null;
            }
        }
        public bool MoveNext()
        {
            return !IsDone();
        }

        public void Reset()
        {
        }

        abstract public bool Update();

        abstract public bool IsDone();
    }

    public abstract class AssetBundleLoadBaseOperation : AssetBundleLoadOperation
    {
        public AsyncOperation m_sceneRequest;
    }

    public class AssetBundleLoadLevelSimulationOperation : AssetBundleLoadBaseOperation
    {
        public AssetBundleLoadLevelSimulationOperation()
        {
        }

        public override bool Update()
        {
            return false;
        }

        public override bool IsDone()
        {

            return true;
        }
    }

    public class AssetBundleLoadLevelOperation : AssetBundleLoadBaseOperation
    {

        protected string m_LevelName;
        protected bool m_IsAdditive;
        protected string m_DownloadingError;

        public AssetBundleLoadLevelOperation(string assetbundleName, string levelName, bool isAdditive)
        {
            m_AssetBundleName = assetbundleName;
            m_LevelName = levelName;
            m_IsAdditive = isAdditive;
        }

        public override bool Update()
        {
            if (m_sceneRequest != null)
                return false;

            LoadedAssetBundle bundle = AssetBundleManager.GetLoadedAssetBundle(m_AssetBundleName, out m_DownloadingError);

            if (m_DownloadingError != null)
            {
#if LogError_Open
            Debug.LogError(m_DownloadingError);
#endif
                return false;
            }

            if (bundle != null)
            {
                try
                {
                    if (m_IsAdditive)
                    {
                        m_sceneRequest = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync(m_LevelName);
                    }
                    else
                    {
                        m_sceneRequest = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync(m_LevelName);
                    }
                }
                catch
                {
#if LogError_Open
                    Debug.LogError("LoadLevel error, m_LevelName " + m_LevelName);
#endif
                }

                return false;
            }

            return true;
        }

        public override bool IsDone()
        {
            // Return if meeting downloading error.
            // m_DownloadingError might come from the dependency downloading.
            if (m_sceneRequest == null && m_DownloadingError != null)
            {
#if LogError_Open
                Debug.LogError(m_DownloadingError);
#endif
                return true;
            }

            if (isStop)
                return true;

            return m_sceneRequest != null && m_sceneRequest.isDone;
        }
    }

    public abstract class AssetBundleLoadAssetOperation : AssetBundleLoadOperation
    {
        public abstract T GetAsset<T>() where T : UnityEngine.Object;
        public abstract T[] GetAllAsset<T>() where T : UnityEngine.Object;
    }

    public class AssetBundleLoadAssetOperationSimulation : AssetBundleLoadAssetOperation
    {
        Object m_SimulatedObject;
        Object[] m_allObject;


        protected float startTime;
        protected float deltaTime = 0f;

        public AssetBundleLoadAssetOperationSimulation(string assetBundleName, string assetName, bool single)
        {
#if UNITY_EDITOR

            startTime = Time.realtimeSinceStartup;

            if (single)
            {
                m_SimulatedObject = AssetDatabase.LoadMainAssetAtPath(assetName);
            }
            else
            {
                m_allObject = AssetDatabase.LoadAllAssetsAtPath(assetName);
            }
#endif
        }

        public override T GetAsset<T>()
        {
            return m_SimulatedObject as T;
        }
        public override T[] GetAllAsset<T>()
        {
            return m_allObject as T[];
        }

        public override bool Update()
        {
            return false;
        }

        public override bool IsDone()
        {
            if ((Time.realtimeSinceStartup - startTime) < deltaTime)
                return false;
            else
                return true;
        }
    }

    public class AssetBundleLoadAssetOperationFull : AssetBundleLoadAssetOperation
    {
        protected string m_AssetName;
        protected string m_DownloadingError;
        protected System.Type m_Type;
        //protected AssetBundleRequest	m_Request = null;
        protected Object asset;
        protected Object[] allAsset;

        public AssetBundleLoadAssetOperationFull(string bundleName, string assetName, System.Type type)
        {
            m_AssetBundleName = bundleName;
            m_AssetName = assetName;
            m_Type = type;

        }

        public override T GetAsset<T>()
        {
            if (asset != null)
                return asset as T;
            else
                return null;
        }

        public override T[] GetAllAsset<T>()
        {
            if (allAsset == null)
            {
                LoadedAssetBundle bundle = AssetBundleManager.GetLoadedAssetBundle(m_AssetBundleName, out m_DownloadingError);
                if (bundle != null && m_DownloadingError == null)
                {
                    try
                    {
                        allAsset = bundle.m_AssetBundle.LoadAllAssets(m_Type);
                    }
                    catch
                    {
#if LogError_Open
                        Debug.LogError("LoadAllAsset error, AssetName " + m_AssetName + " type " + m_Type);
#endif
                        allAsset = null;
                    }
                }
            }

            return allAsset as T[];
        }

        // Returns true if more Update calls are required.
        public override bool Update()
        {
            if (asset != null)
                return false;

            LoadedAssetBundle bundle = AssetBundleManager.GetLoadedAssetBundle(m_AssetBundleName, out m_DownloadingError);

            if (m_DownloadingError != null)
            {
#if LogError_Open
                Debug.LogError(m_DownloadingError);
#endif
                return false;
            }

            if (bundle != null)
            {
                try
                {
                    asset = bundle.m_AssetBundle.LoadAsset(m_AssetName, m_Type);
                }
                catch
                {
#if LogError_Open
                    Debug.LogError("LoadAsset error, AssetName " + m_AssetName + " type " + m_Type);
#endif
                    asset = null;
                }

                return false;
            }
            else
            {
                return true;
            }

        }

        public override bool IsDone()
        {
            //Return if meeting downloading error.
            //m_DownloadingError might come from the dependency downloading.
            if (asset == null && m_DownloadingError != null)
            {
#if LogError_Open
                Debug.LogError(m_DownloadingError);
#endif

                return true;
            }

            if (isStop)
                return true;

            return asset != null;
        }
    }

    public class AssetBundleLoadManifestOperation : AssetBundleLoadAssetOperationFull
    {
        public AssetBundleLoadManifestOperation(string bundleName, string assetName, System.Type type)
            : base(bundleName, assetName, type)
        {
        }

        public override bool Update()
        {
            base.Update();

            if (asset != null)
            {
                AssetBundleManager.AssetBundleManifestObject = GetAsset<AssetBundleManifest>();

                return false;
            }
            else
                return true;
        }
    }
}